package com.pic4493.entities;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.LinkedHashMap;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xmlpull.v1.XmlSerializer;

import android.util.Xml;

/**
 * 业务报文解析器
 */
public class DXml
{
   public static final String RootNodeName = "Message";
   public static final String HeadNodeName = "Head";
   public static final String BodyNodeName = "Body";

   private HeadField _head;
   private BodyField _body;

   public HeadField getHead()
   {
	  return _head;
   }

   public void setHead(HeadField head)
   {
	  this._head = head;
   }

   public BodyField getBody()
   {
	  return _body;
   }

   public void setBody(BodyField body)
   {
	  this._body = body;
   }

   public void AddHead(DHead head)
   {	
	  _head.Clear();
	  _head.AddField("version", head.getVersion());
//	  _head.AddField("posttime", head.getPostTime());
	  _head.AddField("apicode", head.getApiCode());
	  _head.AddField("page", String.valueOf(head.getPage()));
	  _head.AddField("pagesize", String.valueOf(head.getPageSize()));
	  _head.AddField("pagecount", String.valueOf(head.getPageCount()));
	  _head.AddField("channel", head.getChannel());
	  _head.AddField("rspcode", head.getRspCode());
	  _head.AddField("rspmsg", head.getRspMsg());
	  _head.AddField("imei", head.getImei());
	  _head.AddField("userid",head.getUserId());
	  _head.AddField("verify",head.getVerify());
   }

   public DXml()
   {
	  _head = new HeadField();
	  _body = new BodyField();
   }

   public DXml(String xml)
   {
	  this();
	  FromXml(xml);
   }

   // public void FromXml(String xml)
   // {
   // if (xml == null || xml.equals(""))
   // {
   // return;
   // }
   //
   // DocumentBuilderFactory factory = null;
   // DocumentBuilder docBuilder = null;
   // Document doc = null;
   // try
   // {
   // InputStream in = new ByteArrayInputStream(xml.getBytes());
   // factory = DocumentBuilderFactory.newInstance();
   // docBuilder = factory.newDocumentBuilder();
   // doc = docBuilder.parse(in);
   // Element root = doc.getDocumentElement();
   //
   // if (root.getTagName().equals("Result"))
   // {
   // if (root.getFirstChild() != null)
   // {
   // FromRawXml(root.getFirstChild().getNodeValue());
   // }
   // }
   // else if (root.getTagName().equals("Error"))
   // {
   // // getHead().setRespCode(root.getAttribute("ErrId"));
   // // getHead().setRespMsg(root.getAttribute("ErrMsg"));
   // }
   // else
   // {
   // FromRawXml(xml);
   // }
   // }
   // catch (Exception e)
   // {
   //
   // }
   // finally
   // {
   // doc = null;
   // docBuilder = null;
   // factory = null;
   // }
   // }

   public void FromXml(String xml)
   {
	  if (xml == null || xml.equals(""))
	  {
		 return;
	  }

	  DocumentBuilderFactory factory = null;
	  DocumentBuilder docBuilder = null;
	  Document doc = null;
	  try
	  {
		 InputStream in = new ByteArrayInputStream(xml.getBytes());
		 factory = DocumentBuilderFactory.newInstance();
		 factory.setCoalescing(true);
		 docBuilder = factory.newDocumentBuilder();
		 doc = docBuilder.parse(in);
		 Element root = doc.getDocumentElement();

		 // head
		 NodeList nodeList = root.getElementsByTagName("Head");
		 if (nodeList != null && nodeList.getLength() > 0)
		 {
			getHead().FromXml((Element) nodeList.item(0));
		 }

		 // body
		 nodeList = root.getElementsByTagName("Body");
		 if (nodeList != null && nodeList.getLength() > 0)
		 {
			getBody().FromXml((Element) nodeList.item(0));
		 }
	  }
	  catch (Exception e)
	  {
		 e.printStackTrace();
	  }
	  finally
	  {
		 doc = null;
		 docBuilder = null;
		 factory = null;
	  }
   }

   public String toXml()
   {
	  XmlSerializer serializer = Xml.newSerializer();
	  StringWriter writer = new StringWriter();
	  try
	  {
		 serializer.setOutput(writer);
		 serializer.startDocument("utf-8", true);
		 serializer.startTag("", "Message");
		 getHead().ToXml(serializer);
		 getBody().ToXml(serializer);
		 serializer.endTag("", "Message");
		 serializer.endDocument();
		 return writer.toString();
	  }
	  catch (Exception e)
	  {
		 e.printStackTrace();
	  }
	  finally
	  {
		 serializer = null;
		 writer = null;
	  }
	  return null;
   }

   public byte[] toBytes() throws UnsupportedEncodingException
   {
	  return (this.toXml().replace("&#64;", "@")).getBytes("utf-8");
   }

   /**
    * 报文的 Head
    * 
    * @author lichen
    * 
    */
   public class HeadField extends FieldList
   {
	  public HeadField()
	  {
		 setName(DXml.HeadNodeName);
	  }
   }

   /**
    * 报文的 Body
    * 
    * @author lichen
    * 
    */
   public class BodyField extends FieldList
   {
	  public BodyField()
	  {
		 setName(DXml.BodyNodeName);
	  }
   }

   /**
    * 报文的 Field
    * 
    * @author lichen
    * 
    */
   public class Field extends BaseField
   {
	  public Field(String name, String value)
	  {
		 setName(name);
		 setValue(value);
	  }

	  public Field(Node node)
	  {
		 FromXml(node);
	  }

	  @Override
	  public void Clear()
	  {

	  }

	  @Override
	  public void FromXml(Node node)
	  {
		 setName(node.getNodeName());
		 setValue(node.getFirstChild() == null ? "" : node.getFirstChild().getNodeValue());
		 NamedNodeMap attrs = node.getAttributes();
		 int size = attrs.getLength();
		 for (int i = 0; i < size; i++)
		 {
			getAttributes().put(attrs.item(i).getNodeName(), attrs.item(i).getNodeValue());
		 }
	  }

	  @Override
	  public void ToXml(XmlSerializer xs)
	  {
		 try
		 {
			xs.startTag("", getName());

			if (getAttributes().size() > 0)
			{
			   LinkedHashMap<String, String> map = getAttributes();
			   for (String name : map.keySet())
			   {
				  xs.attribute("", name, map.get(name));
			   }
			}

			xs.text((getValue() == null || getValue().equals("")) ? "" : getValue());
			xs.endTag("", getName());
		 }
		 catch (Exception e)
		 {
			e.printStackTrace();
		 }
	  }
   }

   /**
    * 报文的 FieldList
    * 
    * @author lichen
    * 
    */
   public class FieldList extends BaseField
   {
	  protected ArrayList<BaseField> _childs;

	  /**
	   * 所有的孩子，包括 Field FieldList
	   * 
	   * @return
	   */
	  public BaseField[] getChilds()
	  {
		 BaseField[] fields = new BaseField[_childs.size()];
		 return (BaseField[]) _childs.toArray(fields);
	  }

	  /**
	   * 所有的 Field 值
	   * 
	   * @return
	   */
	  public Field[] getFields()
	  {
		 ArrayList<Field> fields = new ArrayList<Field>();
		 int size = _childs.size();
		 for (int i = 0; i < size; i++)
		 {
			if (_childs.get(i) instanceof Field)
			{
			   fields.add((Field) _childs.get(i));
			}
		 }
		 Field[] result = new Field[fields.size()];
		 return (Field[]) fields.toArray(result);
	  }

	  /**
	   * 所有的 FieldList 值
	   * 
	   * @return
	   */
	  public FieldList[] getFieldLists()
	  {
		 ArrayList<FieldList> fieldLists = new ArrayList<FieldList>();
		 int size = _childs.size();
		 for (int i = 0; i < size; i++)
		 {
			if (_childs.get(i) instanceof FieldList)
			{
			   fieldLists.add((FieldList) _childs.get(i));
			}
		 }
		 FieldList[] result = new FieldList[fieldLists.size()];
		 return (FieldList[]) fieldLists.toArray(result);
	  }

	  public FieldList()
	  {
		 _childs = new ArrayList<BaseField>();
	  }

	  public FieldList(String name)
	  {
		 this();
		 setName(name);
	  }

	  public FieldList(Node node)
	  {
		 this();
		 FromXml(node);
	  }

	  /**
	   * 根据索引获取 FieldList
	   * 
	   * @param index
	   * @return
	   */
	  public FieldList GetFieldList(int index)
	  {
		 FieldList[] array = getFieldLists();
		 if (array != null && index < array.length)
		 {
			return array[index];
		 }
		 else
		 {
			return null;
		 }
	  }

	  /**
	   * 获取第一个 FieldList
	   * 
	   * @return
	   */
	  public FieldList GetFirstFieldList()
	  {
		 return GetFieldList(0);
	  }

	  /**
	   * 根据名称获取 Field 或 FieldList
	   * 
	   * @param name
	   * @return
	   */
	  public BaseField GetChild(String name)
	  {
		 int size = _childs.size();
		 for (int i = 0; i < size; i++)
		 {
			if (_childs.get(i).getName().equals(name))
			{
			   return _childs.get(i);
			}
		 }
		 return null;
	  }

	  /**
	   * 根据名称获取 Field 或 FieldList
	   * 
	   * @param name
	   * @return
	   */
	  public BaseField[] GetChilds(String name)
	  {
		 ArrayList<BaseField> list = new ArrayList<BaseField>();
		 int size = _childs.size();
		 for (int i = 0; i < size; i++)
		 {
			if (_childs.get(i).getName().equals(name))
			{
			   list.add(_childs.get(i));
			}
		 }
		 BaseField[] result = new BaseField[list.size()];
		 return (BaseField[]) list.toArray(result);
	  }

	  /**
	   * 根据名称获取 FieldList
	   * 
	   * @param name
	   * @return
	   */
	  public FieldList GetFieldList(String name)
	  {
		 int size = _childs.size();
		 for (int i = 0; i < size; i++)
		 {
			BaseField bf = _childs.get(i);
			if (bf instanceof FieldList && bf.getName().equals(name))
			{
			   return (FieldList) bf;
			}
		 }
		 return null;
	  }

	  /**
	   * 根据名称获取 FieldLists
	   * 
	   * @param name
	   * @return
	   */
	  public FieldList[] GetFieldLists(String name)
	  {
		 ArrayList<FieldList> fieldLists = new ArrayList<FieldList>();
		 int size = _childs.size();
		 for (int i = 0; i < size; i++)
		 {
			BaseField bf = _childs.get(i);
			if (bf instanceof FieldList && bf.getName().equals(name))
			{
			   fieldLists.add((FieldList) bf);
			}
		 }
		 FieldList[] result = new FieldList[fieldLists.size()];
		 return (FieldList[]) fieldLists.toArray(result);
	  }

	  /**
	   * 根据 Field 名获取 Field
	   * 
	   * @param fieldName
	   * @return
	   */
	  public Field GetField(String fieldName)
	  {
		 int size = _childs.size();
		 for (int i = 0; i < size; i++)
		 {
			BaseField bf = _childs.get(i);
			if (bf instanceof Field && bf.getName().equals(fieldName))
			{
			   return (Field) bf;
			}
		 }
		 return null;
	  }

	  /**
	   * 根据 Field 名获取 Field
	   * 
	   * @param fieldName
	   * @return
	   */
	  public Field[] GetFields(String fieldName)
	  {
		 ArrayList<Field> fields = new ArrayList<Field>();
		 int size = _childs.size();
		 for (int i = 0; i < size; i++)
		 {
			BaseField bf = _childs.get(i);
			if (bf instanceof FieldList && bf.getName().equals(fieldName))
			{
			   fields.add((Field) bf);
			}
		 }
		 Field[] result = new Field[fields.size()];
		 return (Field[]) fields.toArray(result);
	  }

	  /**
	   * 根据 Field 名获取其值
	   * 
	   * @param fieldName
	   * @return
	   */
	  public String GetFieldValue(String fieldName)
	  {
		 Field f = GetField(fieldName);
		 if (f != null)
		 {
			return f.getValue();
		 }
		 else
		 {
			return null;
		 }
	  }

	  /**
	   * 根据 Field 名获取其值
	   * 
	   * @param fieldName
	   * @return
	   */
	  public int GetFieldInt32(String fieldName)
	  {
		 Field f = GetField(fieldName);
		 if (f != null)
		 {
			return (f.getValue() == null || f.getValue().equals("")) ? 0 : Integer.valueOf(f.getValue().trim());
		 }
		 else
		 {
			return 0;
		 }
	  }

	  /**
	   * 根据 Field 名获取其值
	   * 
	   * @param fieldName
	   * @return
	   */
	  public long GetFieldInt64(String fieldName)
	  {
		 Field f = GetField(fieldName);
		 if (f != null)
		 {
			return (f.getValue() == null || f.getValue().equals("")) ? 0 : Long.valueOf(f.getValue().trim());
		 }
		 else
		 {
			return 0;
		 }
	  }

	  /**
	   * 根据 Field 名获取其值
	   * 
	   * @param fieldName
	   * @return
	   */
	  public float GetFieldFloat(String fieldName)
	  {
		 Field f = GetField(fieldName);
		 if (f != null)
		 {
			return (f.getValue() == null || f.getValue().equals("")) ? 0 : Float.valueOf(f.getValue().trim());
		 }
		 else
		 {
			return 0;
		 }
	  }

	  /**
	   * 加入 Field
	   * 
	   * @param name
	   * @param value
	   * @return
	   */
	  public Field AddField(String name, String value)
	  {
		 return AddField(new Field(name, value));
	  }

	  /**
	   * 加入 Field
	   * 
	   * @param field
	   * @return
	   */
	  public Field AddField(Field field)
	  {
		 if (field != null)
		 {
			field.setOwner(this);

			// 添加
			_childs.add(field);
		 }
		 return field;
	  }

	  /**
	   * 加入 FieldLisT
	   * 
	   * @param name
	   * @return
	   */
	  public FieldList AddFieldList(String name)
	  {
		 return AddFieldList(new FieldList(name));
	  }

	  /**
	   * 加入 FieldList
	   * 
	   * @param fl
	   * @return
	   */
	  public FieldList AddFieldList(FieldList fl)
	  {
		 if (fl != null)
		 {
			fl.setOwner(this);

			// 添加
			_childs.add(fl);
		 }
		 return fl;
	  }

	  /**
	   * 加入 Child
	   * 
	   * @param bf
	   * @return
	   */
	  public BaseField AddChild(BaseField bf)
	  {
		 if (bf == null)
		 {
			return null;
		 }

		 if (bf instanceof DXml.Field)
		 {
			return AddField((DXml.Field) bf);
		 }
		 else if (bf instanceof DXml.FieldList)
		 {
			return AddFieldList((DXml.FieldList) bf);
		 }

		 return null;
	  }

	  /**
	   * 根据名称移除 Field
	   * 
	   * @param name
	   */
	  public void RemoveField(String name)
	  {
		 DXml.Field f = GetField(name);
		 if (f != null)
		 {
			_childs.remove(f);
		 }
	  }

	  /**
	   * 根据名称移除 FieldList
	   * 
	   * @param name
	   */
	  public void RemoveFieldList(String name)
	  {
		 DXml.FieldList fl = GetFieldList(name);
		 if (fl != null)
		 {
			_childs.remove(fl);
		 }
	  }

	  /**
	   * 清空
	   */
	  @Override
	  public void Clear()
	  {
		 if (this != null && this.getChilds().length > 0)
		 {
			for (BaseField f : this.getChilds())
			{
			   f.Clear();
			}
		 }
		 _childs.clear();
	  }

	  @Override
	  public void FromXml(Node node)
	  {
		 // 子节点总数
		 int childCount = 0;

		 // 节点属性集
		 this.setName(node.getNodeName());

		 NamedNodeMap attrs = node.getAttributes();
		 int size = attrs.getLength();
		 for (int i = 0; i < size; i++)
		 {
			getAttributes().put(attrs.item(i).getNodeName(), attrs.item(i).getNodeValue());
		 }

		 // 子节点
		 int childNum = node.getChildNodes().getLength();
		 for (int i = 0; i < childNum; i++)
		 {
			Node childNode = node.getChildNodes().item(i);
			if (childNode.getNodeType() == Node.ELEMENT_NODE)
			{
			   if (HasChildNodes(childNode))
			   {
				  AddFieldList(new FieldList(childNode));
			   }
			   else
			   {
				  AddField(new Field(childNode));
			   }
			   childCount++;
			}
		 }

		 // 无子节点
		 if (childCount == 0)
		 {
			// TO-DO 无子节点
			this.setValue(node.getFirstChild() == null ? "" : node.getFirstChild().getNodeValue());
		 }
	  }

	  @Override
	  public void ToXml(XmlSerializer xs)
	  {
		 try
		 {
			xs.startTag("", getName());

			if (getAttributes().size() > 0)
			{
			   LinkedHashMap<String, String> map = getAttributes();
			   for (String name : map.keySet())
			   {
				  xs.attribute("", name, map.get(name));
			   }
			}

			// 值为空
			if (getValue() != null && !getValue().equals(""))
			{
			   xs.text((getValue() == null || getValue().equals("")) ? "" : getValue());
			}
			else
			{
			   // 子元素
			   BaseField[] childs = this.getChilds();
			   int size = childs.length;
			   for (int i = 0; i < size; i++)
			   {
				  childs[i].ToXml(xs);
			   }
			}
			xs.endTag("", getName());
		 }
		 catch (Exception e)
		 {

		 }
	  }
   }

   /**
    * 检查节点是否有子节点
    * 
    * @param node
    * @return
    */
   public boolean HasChildNodes(Node node)
   {
	  int size = node.getChildNodes().getLength();
	  if (size < 1)
	  {
		 return false;
	  }
	  NodeList nList = node.getChildNodes();
	  for (int i = 0; i < size; i++)
	  {
		 if (nList.item(i).getNodeType() == Node.ELEMENT_NODE)
		 {
			return true;
		 }
	  }
	  return false;
   }

   /**
    * Field FieldList 基类
    * 
    * @author lichen
    * 
    */
   public abstract class BaseField
   {

	  /**
	   * 存放扩展属性
	   */
	  protected LinkedHashMap<String, String> _attributes;

	  private BaseField _Owner;
	  private String _Name;
	  private String _Value;
	  private Object _Tag;

	  public BaseField getOwner()
	  {
		 return _Owner;
	  }

	  public void setOwner(BaseField Owner)
	  {
		 this._Owner = Owner;
	  }

	  public String getName()
	  {
		 return _Name;
	  }

	  public void setName(String Name)
	  {
		 this._Name = Name;
	  }

	  public String getValue()
	  {
		 return _Value;
	  }

	  public void setValue(String Value)
	  {
		 this._Value = Value;
	  }

	  public Object getTag()
	  {
		 return _Tag;
	  }

	  public void setTag(Object Tag)
	  {
		 this._Tag = Tag;
	  }

	  /**
	   * 
	   * 扩展属性
	   */
	  public LinkedHashMap<String, String> getAttributes()
	  {
		 if (_attributes == null)
		 {
			_attributes = new LinkedHashMap<String, String>();
		 }
		 return _attributes;
	  }

	  public abstract void Clear();

	  public abstract void FromXml(Node node);

	  public abstract void ToXml(XmlSerializer xs);
   }
}